﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sparrow.Extensions;
using System.Configuration;



namespace Sparrow.Web.Router
{
    public class WebRouter
    {
        public WebRouter()
        {
            this.Parameters = new string[0];
        }

        public WebRouter(WebRouter parentRouter)
        {
            this._ParentRouter = parentRouter;
        }

        public virtual string Id
        {
            get;
            set;
        }

        WebRouter _ParentRouter;
        public virtual WebRouter ParentRouter
        {
            get
            {
                this._ParentRouter = this._ParentRouter.LazyInit(() => Factory.Proivder.ParentRouter(this));
                return this._ParentRouter;
            }
            set
            {
                this._ParentRouter = value;              
                this.Reroute();                
            }
        }

        public virtual IQueryable<WebRouter> ChildRouters
        {
            get
            {
                return Factory.Proivder.ChildRouters(this);
            }
        }

        public virtual IQueryable<WebRouter> SiblingRouters
        {
            get
            {
                if (this.ParentRouter == null)
                {
                    return Factory.Proivder.RootRouters();
                }
                else
                {
                    return this.ParentRouter.ChildRouters;
                }
            }
        }

        public virtual IQueryable<JumpableWebRouter> JumpableRouters
        {
            get
            {
                return Factory.Proivder.JumpableRouters(this);
            }
        }

        public virtual IQueryable<WebRouterModule> Modules
        {
            get
            {
                return Factory.Proivder.RouterModules(this);
            }
        }


        public virtual bool Add(JumpableWebRouter router)
        {
            return Factory.Proivder.Add(this,router);
        }

        public virtual bool Remove(JumpableWebRouter router)
        {
            return Factory.Proivder.Remove(this, router);
        }

        public virtual bool Add(WebRouter router)
        {
            router.ParentRouter = this;
            return Factory.Proivder.Add(router);
        }

        public virtual bool Remove(WebRouter router)
        {
            router.ParentRouter = this;
            return Factory.Proivder.Remove(router);

        }

        public virtual bool Add(WebRouterModule action)
        {
            return Factory.Proivder.AddRouterModule(this, action);
        }

        public virtual bool Remove(WebRouterModule action)
        {
            return Factory.Proivder.RemoveRouterModule(this, action);
        }


        public virtual string Name
        {
            get;
            set;
        }

        int _Sequence = 1;
        public virtual int Sequence 
        {
            get
            {
                return this._Sequence;
            }
            set
            {
                if (value > 0)
                {
                    this._Sequence = value;
                }
            }
        }


        public virtual string RoutePath
        {
            get;
            set;
        }

        public virtual void Reroute()
        {
            if (this.ParentRouter == null)
            {
                this.RoutePath = "1";
            }
            else
            {
                this.RoutePath = this.ParentRouter.RoutePath + this.ParentRouter.Sequence.ToString();
            }
        }

  

        public virtual string Url
        {
            get
            {
                if (this.ParentRouter != null)
                {
                    return this.ParentRouter.Url + "/" + this.Name;
                }
                else
                {
                    return Configration.RootRouter + System.Web.HttpUtility.UrlEncode(this.Name);
                }
            }
        }

        public string[] Parameters
        {
            get;
            set;
        }

        public virtual WebRouter Route(WebRouterModule action)
        {
            var node = this.JumpableRouters
                .Where(i => i.RouterModule.Name == action.Name)
                .Select(i=>i.TargetRouter)
                .FirstOrDefault();

            if (node != null)
            {
                return node;
            }
            else
            {
                    /*
                         *  (1)1   --   (11)1  --  (111)1  -- (1111)1
                         *                                 -- (1111)2
                         *                     --  (111)2
                         *                     --  (111)3
                         *              (11)2  --  (112)1
                         *                     --  (112)2
                         *                     
                         *  (1)2   --   (12)1  --  (121)1  -- (1211)1
                         *                                 -- (1211)2
                         *                         (121)2 
                         * 
                         * 
                         * 
                         * */

                //1. try to look up in in ParentNode
                if (this.ParentRouter != null)
                {
                    if (this.ParentRouter.Modules.Any(i => i.Name == action.Name))
                    {
                        return this.ParentRouter;
                    }
                }

                //2. try to look up in ChildNodes
                node = this.ChildRouters
                    .Where(i => i.Modules.Any(v => v.Name == action.Name))
                    .OrderByDescending(i=>i.Sequence)
                    .FirstOrDefault();

                if (node != null)
                {
                    return node;
                }

                //3. try to look up in SiblingNodes
                node = this.SiblingRouters
                    .Where(i => i.Modules.Any(v => v.Name == action.Name))
                    .OrderByDescending(i => i.Sequence)
                    .FirstOrDefault();

                if (node != null)
                {
                    return node;
                }



                var minRouteValue = Int64.MaxValue;
                foreach (var i in action.Routers)
                {
                    if (i.RoutePath == this.RoutePath)
                    {
                        var routeValue = Math.Abs(this.Sequence - i.Sequence);
                        if (routeValue < minRouteValue)
                        {
                            minRouteValue = routeValue;
                            node = i;
                        }
                    }
                    else
                    {
                        //max route deep is 19
                        var routeValue = Math.Abs(Int64.Parse(this.RoutePath.Fix(19)) - Int64.Parse(this.RoutePath.Fix(19)))
                            + i.Sequence + this.Sequence;

                        if (routeValue < minRouteValue)
                        {
                            minRouteValue = routeValue;
                            node = i;
                        }
                    }
                }

                return node;
            }
        }


        
    }
}
